﻿using System.Collections.Generic;
using System.Linq;
using HHPS.CreditEducation.DataProvider;
using HHPS.CreditEducation.Frameworks.Commons;
using HHPS.CreditEducation.Frameworks.Constants;

namespace HHPS.CreditEducation.Business
{
    public partial class Business
    {
        #region -- Get Subject --

        /// <summary>
        /// This function shows list of Subjects.
        /// </summary>
        /// <returns></returns>
        public List<Subject> GetListSubject()
        {
            return DataContex != null ? DataContex.Subjects.ToList() : null;
        }
        public List<Subject> GetListSubject(int withoutId)
        {
            var listWithoutId = DataContex.SubjectRequires.Where(sr => sr.IdSubjectRequire == withoutId).Select(sr => sr.IdSubject).ToList();
            listWithoutId.AddRange(DataContex.SubjectRequires.Where(sr => sr.IdSubject == withoutId).Select(sr => sr.IdSubjectRequire));
            return DataContex != null ? DataContex.Subjects.Where(s => s.Id != withoutId && !listWithoutId.Contains(s.Id)).ToList() : null;
        }

        /// <summary>
        /// This function shows list of Subjects by keyword.
        /// </summary>
        /// <param name="keyNameSubject"></param>
        /// <returns></returns>
        public List<Subject> GetListSubjectByKeyNameSubject(string keyNameSubject)
        {
            return string.IsNullOrEmpty(keyNameSubject)
                       ? DataContex.Subjects.ToList()
                       : DataContex.Subjects.Where(s => s.Name.ToLower().Contains(keyNameSubject.ToLower())).ToList();
        }

        /// <summary>
        /// This function shows list of Subjects by kind of subject.
        /// </summary>
        /// <param name="idKindOfSubject"></param>
        /// <param name="keyword"></param>
        /// <returns></returns>
        public List<Subject> GetListSubjectByKindOfSubject(int idKindOfSubject, string keyword)
        {
            return DataContex != null && idKindOfSubject > 0
                     ? DataContex.Subjects.Where(s => s.IdKindOfSubject == idKindOfSubject && s.Name.ToLower().Contains(keyword)).ToList()
                     : null;
        }

        #endregion

        #region Common

        private static bool SubjectCommonValidator(Subject subject, out string message)
        {
            if (string.IsNullOrWhiteSpace(subject.Name))
            {
                message = string.Format(ConstantMessages.RequireFieldIsBlank, "tên Môn học");
                return false;
            }

            if (subject.Name.Length >= 50)
            {
                message = string.Format(ConstantMessages.FieldDataOverMaxLength, "tên Môn học", 50);
                return false;
            }

            if (subject.NumberOfCredit <= 0)
            {
                message = string.Format(ConstantMessages.DataUnderMinValue, "Số tín chỉ");
                return false;
            }

            if (subject.IdKindOfSubject <= 0)
            {
                message = string.Format(ConstantMessages.CanNotIdentifyItem);
                return false;
            }

            message = string.Empty;
            return true;
        }

        #endregion

        #region --Add Subject--

        /// <summary>
        /// This function checks validate of add a new subject into a faculty
        ///     Is Facutly exsit?
        ///     Is new name major same as orther major
        /// </summary>
        /// <param name="subject"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public bool AddNewSubjectValidator(Subject subject, out string message)
        {
            if (!SubjectCommonValidator(subject, out message)) return false;

            if (DataContex.Subjects.Any(s => s.Name.ToLower() == subject.Name.ToLower()))
            {
                message = string.Format(ConstantMessages.ItemIsExisted, subject.Name);
                return false;
            }

            return true;
        }

        /// <summary>
        /// This function adds new a major in a facutly
        /// </summary>
        /// <param name="subject"></param>
        public void AddNewSubject(Subject subject)
        {
            DataContex.Subjects.AddObject(subject);
            DataContex.SaveChanges();
        }

        #endregion

        #region --Edit Subject--

        /// <summary>
        /// This fuction check validate of edit a major function 
        /// </summary>
        /// <param name="subject"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public bool EditSubjectValidator(Subject subject, out string message)
        {
            var id = subject.Id;
            if (!DataContex.Subjects.Any(s => s.Id == id))
            {
                message = ConstantMessages.CanNotIdentifyItem;
                return false;
            }

            if (!SubjectCommonValidator(subject, out message)) return false;

            if (DataContex.Subjects.Any(s => s.Name.ToLower() == subject.Name.ToLower() && s.Id != subject.Id))
            {
                message = string.Format(ConstantMessages.ItemIsExisted, subject.Name);
                return false;
            }

            return true;
        }

        /// <summary>
        /// This fuction edits a subject
        /// </summary>
        /// <param name="subject"></param>
        public bool EditSubject(Subject subject)
        {
            var id = subject.Id;
            var updateSubject = DataContex.Subjects.SingleOrDefault(s => s.Id == id);

            if (updateSubject == null)
                return false;

            updateSubject.Name = subject.Name;
            updateSubject.NumberOfCredit = subject.NumberOfCredit;
            updateSubject.IdKindOfSubject = subject.IdKindOfSubject;
            DataContex.SaveChanges();
            return true;
        }

        #endregion

        #region --Delete Subject--

        /// <summary>
        /// This fuction checks validate of delete a Subject fuction
        /// </summary>
        /// <param name="subjects"></param>
        /// <param name="message"></param>
        /// <returns></returns>       
        public bool DeleteSubjectValidator(IEnumerable<Subject> subjects, out string message)
        {
            const string intialize = "Môn học: ";
            var itemsCannotIdentify = (from subject in subjects
                                       let id = subject.Id
                                       where !DataContex.Subjects.Any(s => s.Id == id)
                                       select subject).Aggregate(intialize, (current, subject) => current + (subject.Name + ", "));

            if (itemsCannotIdentify != intialize)
            {
                message = string.Format(ConstantMessages.SomeItemsCanNotIdentify, itemsCannotIdentify.TrimEnd(','));
                return false;
            }

            var itemsInUse = (from subject in subjects
                              let id = subject.Id
                              where DataContex.SubjectRequires.Any(s => s.IdSubject == id)
                              select subject).Aggregate(intialize, (current, subject) => current + (subject.Name + ", "));

            if (itemsInUse != intialize)
            {
                message = string.Format(ConstantMessages.SomeItemsInUseCanNotDelete, itemsInUse.TrimEnd(','));
                return false;
            }

            message = string.Empty;
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="subjects"></param>
        public void DeleteSubjects(List<Subject> subjects)
        {
            for (var i = subjects.Count - 1; i >= 0; i--)
            {
                var id = subjects[i].Id;
                var deleteSubject = DataContex.Subjects.Single(s => s.Id == id);

                DataContex.Subjects.DeleteObject(deleteSubject);
            }
            DataContex.SaveChanges();
        }

        #endregion
    }
}